///代码基本来自LearnOpenGL网站
#ifndef MESH_H
#define MESH_H
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <string>
#include <vector>
#include<BHXJGLHelper/bhxjglinclude.h>
#include<BHXJGLHelper/bhxjglshader.h>
#include<BHXJControls_global.h>
using namespace std;

struct BHXJCONTROLS_EXPORT Vertex {
    glm::vec3 Position;
    glm::vec3 Normal;
    glm::vec2 TexCoords;
};
struct BHXJCONTROLS_EXPORT Texture {
    unsigned int id;
    string type;
    aiString path;
};

class BHXJCONTROLS_EXPORT BHXJMesh {
public:
    /*  网格数据  */
    vector<Vertex> vertices;
    vector<unsigned int> indices;
    vector<Texture> textures;
    /*  函数  */
    BHXJMesh(BHXJGLFUN *glcore,vector<Vertex> vertices, vector<unsigned int> indices, vector<Texture> textures)
    {
        this->gl=glcore;
        this->vertices = vertices;
        this->indices = indices;
        this->textures = textures;

        setupMesh();
    }

    void Draw(BHXJGLShader shader)
    {
        // bind appropriate textures
        unsigned int diffuseNr  = 1;
        unsigned int specularNr = 1;
        unsigned int normalNr   = 1;
        unsigned int heightNr   = 1;
        for(unsigned int i = 0; i < textures.size(); i++)
        {
            gl->glActiveTexture(GL_TEXTURE0 + i); // active proper texture unit before binding
            // retrieve texture number (the N in diffuse_textureN)
            string number;
            string name = textures[i].type;
            if(name == "texture_diffuse")
                number = std::to_string(diffuseNr++);
            else if(name == "texture_specular")
                number = std::to_string(specularNr++); // transfer unsigned int to stream
            else if(name == "texture_normal")
                number = std::to_string(normalNr++); // transfer unsigned int to stream
            else if(name == "texture_height")
                number = std::to_string(heightNr++); // transfer unsigned int to stream

            // now set the sampler to the correct texture unit
           gl->glUniform1i(gl->glGetUniformLocation(shader.ID, ("material."+name + number).c_str()), static_cast<int>(i));
            //gl->glUniform1i(gl->glGetUniformLocation(shader.ID, (name + number).c_str()), static_cast<int>(i));
            // and finally bind the texture
            glBindTexture(GL_TEXTURE_2D, textures[i].id);
        }

        // 绘制网格
        gl->glBindVertexArray(VAO);
        gl->glDrawElements(GL_TRIANGLES, static_cast<int>(indices.size()), GL_UNSIGNED_INT, nullptr);
        gl->glBindVertexArray(0);
    }
private:

    BHXJGLFUN *gl;
    /*  渲染数据  */
    unsigned int VAO, VBO, EBO;
    /*  函数  */
    void setupMesh()
    {

        gl->glGenVertexArrays(1, &VAO);
        gl->glGenBuffers(1, &VBO);
        gl->glGenBuffers(1, &EBO);

        gl->glBindVertexArray(VAO);
        gl->glBindBuffer(GL_ARRAY_BUFFER, VBO);

        gl->glBufferData(GL_ARRAY_BUFFER, static_cast<int>(vertices.size() * sizeof(Vertex)) , &vertices[0], GL_STATIC_DRAW);

        gl->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
        gl->glBufferData(GL_ELEMENT_ARRAY_BUFFER, static_cast<int>(indices.size() * sizeof(unsigned int)),
                         &indices[0], GL_STATIC_DRAW);

        // 顶点位置
        gl->glEnableVertexAttribArray(0);
        gl->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), nullptr);
        // 顶点法线
        gl->glEnableVertexAttribArray(1);
        gl->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(offsetof(Vertex, Normal)));
        // 顶点纹理坐标
        gl->glEnableVertexAttribArray(2);
        gl->glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(offsetof(Vertex, TexCoords)));

        gl->glBindVertexArray(0);
    }
};

#endif // MESH_H
